/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
 */

package com.zyj.hms.pushsample;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.huawei.hms.push.ohos.HmsMessageService;
import com.huawei.hms.push.ohos.ZBaseException;
import com.huawei.hms.push.ohos.ZRemoteMessage;
import com.zyj.hms.pushsample.utils.Const;
import com.zyj.hms.pushsample.utils.LogUtil;
import com.zyj.hms.pushsample.utils.ThreadPoolUtil;
import com.zyj.hms.pushsample.utils.WakeUpUtils;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.IntentParams;
import ohos.aafwk.content.Operation;
import ohos.agp.components.Text;
import ohos.bundle.ElementName;
import ohos.event.commonevent.*;
import ohos.event.intentagent.IntentAgent;
import ohos.event.intentagent.IntentAgentConstant;
import ohos.event.intentagent.IntentAgentHelper;
import ohos.event.intentagent.IntentAgentInfo;
import ohos.event.notification.NotificationHelper;
import ohos.event.notification.NotificationRequest;
import ohos.event.notification.NotificationSlot;
import ohos.event.notification.NotificationUserInput;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.net.HttpResponseCache;
import ohos.net.NetHandle;
import ohos.net.NetManager;
import ohos.rpc.RemoteException;
import ohos.utils.PacMap;
import ohos.utils.net.Uri;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DemoHmsMessageServiceAbility extends HmsMessageService {
    private static final String TAG = MainAbility.class.getSimpleName();
    private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD000F00, TAG);
    private NotificationEventSubscriber eventSubscriber;
    private WakeUpUtils wakeUpUtils;
    private NetManager netManager;

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        wakeUpUtils = new WakeUpUtils();
        subscribeCommonEvent();
        defineNotificationSlot();
    }

    @Override
    public void onMessageReceived(ZRemoteMessage message) {
        LogUtil.i("::onMessageReceived,  data: " + message.getData());
        //测试远程唤醒
        wakeUpUtils.wakeup(result -> requestMsgBack(result, message.getDataOfMap()));
    }

    @Override
    public void onNewToken(String token) {
        LogUtil.i("DemoHmsMessageServiceAbility::onNewToken token:" + token);
    }

    @Override
    public void onTokenError(Exception exception) {
        if (exception instanceof ZBaseException) {
            LogUtil.i("DemoHmsMessageServiceAbility::onTokenError errCode:" +
                    ((ZBaseException) exception).getErrorCode());
        }
    }

    @Override
    public void onStop() {
        super.onStop();
        unSubscribeCommonEvent();
    }

    private void requestMsgBack(String wakeUpResult, Map<String, String> data) {
        publishNotification(wakeUpResult, 0x1000001);
        String pushId = data.get("pushId");
        String url = "https://fc-mp-67dcfd0c-c143-49dd-81a6-3d6aabd6ef7b.next.bspapp.com/com-power";
        HashMap<String, Object> datas = new HashMap<>();
        datas.put("action", "sendHmsMsgBack");
        datas.put("pushId", pushId);
        datas.put("wakeUpResult", wakeUpResult);
        netRequest(url, datas);
    }

    private void defineNotificationSlot() {
        NotificationSlot notificationSlot = new NotificationSlot(Const.SLOT_ID, Const.SLOT_NAME, NotificationSlot.LEVEL_HIGH);
        notificationSlot.setEnableVibration(true);
        notificationSlot.setLockscreenVisibleness(NotificationRequest.VISIBLENESS_TYPE_PUBLIC);
        Uri uri = Uri.parse(Const.SOUND_URI);
        notificationSlot.setSound(uri);
        try {
            NotificationHelper.addNotificationSlot(notificationSlot);
        } catch (RemoteException ex) {
            HiLog.error(LABEL_LOG, "%{public}s", "defineNotificationSlot remoteException.");
        }
    }

    private void subscribeCommonEvent() {
        MatchingSkills skills = new MatchingSkills();
        skills.addEvent(Const.NOTIFICATION_ACTION);
        CommonEventSubscribeInfo subscribeInfo = new CommonEventSubscribeInfo(skills);
        subscribeInfo.setThreadMode(CommonEventSubscribeInfo.ThreadMode.HANDLER);
        eventSubscriber = new NotificationEventSubscriber(subscribeInfo, this);
        try {
            CommonEventManager.subscribeCommonEvent(eventSubscriber);
        } catch (RemoteException e) {
            HiLog.error(LABEL_LOG, "%{public}s", "subscribeCommonEvent remoteException.");
        }
    }

    private void unSubscribeCommonEvent() {
        try {
            CommonEventManager.unsubscribeCommonEvent(eventSubscriber);
        } catch (RemoteException e) {
            HiLog.error(LABEL_LOG, "%{public}s", "unSubscribeCommonEvent remoteException.");
        }
    }

    private void netRequest(String urlString, HashMap<String, Object> params) {
        netManager = NetManager.getInstance(null);
        if (!netManager.hasDefaultNet()) {
            return;
        }
        ThreadPoolUtil.submit(() -> {
            NetHandle netHandle = netManager.getDefaultNet();
            //netManager.addDefaultNetStatusCallback(callback);
            HttpURLConnection connection = null;
            try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
                URL url = new URL(urlString);
                URLConnection urlConnection = netHandle.openConnection(url, java.net.Proxy.NO_PROXY);
                if (urlConnection instanceof HttpURLConnection) {
                    connection = (HttpURLConnection) urlConnection;
                }
                connection.setDoOutput(true);
                connection.setRequestMethod("POST");
                connection.setRequestProperty("Content-Type", "application/json");
                connection.connect();

                // 创建ObjectMapper对象
                ObjectMapper mapper = new ObjectMapper();
                ObjectWriter writer = mapper.writer();
                String postData = writer.writeValueAsString(params);
//                String postData = "{\"action\":\"sendHmsMsgBack\",\"pushId\":\"65ffbff7213929f86649b7b7\"}";
                byte[] outputInBytes = postData.getBytes("UTF-8");

                // 发送请求数据
                try (OutputStream out = connection.getOutputStream()) {
                    out.write(outputInBytes);
                }

                try (InputStream inputStream = urlConnection.getInputStream()) {
                    byte[] cache = new byte[2 * 1024];
                    int len = inputStream.read(cache);
                    while (len != -1) {
                        outputStream.write(cache, 0, len);
                        len = inputStream.read(cache);
                    }
                } catch (IOException e) {
                    HiLog.error(LABEL_LOG, "%{public}s", "netRequest inner IOException");
                }
                String result = new String(outputStream.toByteArray());
                //getUITaskDispatcher().asyncDispatch(() -> notify2_reply.setText(result));
                publishNotification(result, 0x1000002);
                HttpResponseCache.getInstalled().flush();
            } catch (IOException e) {
                HiLog.error(LABEL_LOG, "%{public}s", "netRequest IOException");
            }
        });
    }

    private void publishNotification(String result, int notificationId) {
        NotificationRequest request = new NotificationRequest(notificationId).setSlotId(Const.SLOT_ID)
                .setTapDismissed(true);
        request.setContent(createNotificationContent(Const.NOTIFICATION_TITLE, Const.NOTIFICATION_CONTENT + result));
        IntentAgent intentAgent = createIntentAgent(MainAbility.class.getName(),
                IntentAgentConstant.OperationType.START_ABILITY);
        request.setIntentAgent(intentAgent);
        try {
            NotificationHelper.publishNotification(request);
        } catch (RemoteException ex) {
            HiLog.error(LABEL_LOG, "%{public}s", "publishNotification remoteException.");
        }
    }

    private IntentAgent createIntentAgent(String ability, IntentAgentConstant.OperationType operationType) {
        Intent intent = new Intent();
        Operation operation = new Intent.OperationBuilder().withAction(Const.NOTIFICATION_ACTION).build();
        intent.setOperation(operation);
        if (operationType != IntentAgentConstant.OperationType.SEND_COMMON_EVENT) {
            intent.setElement(new ElementName("", Const.BUNDLE_NAME, ability));
        }
        List<Intent> intents = new ArrayList<>();
        intents.add(intent);
        IntentAgentInfo agentInfo = new IntentAgentInfo(Const.REQUEST_CODE, operationType,
                IntentAgentConstant.Flags.UPDATE_PRESENT_FLAG, intents, new IntentParams());
        return IntentAgentHelper.getIntentAgent(getContext(), agentInfo);
    }

    private NotificationRequest.NotificationContent createNotificationContent(String title, String text) {
        NotificationRequest.NotificationNormalContent content
                = new NotificationRequest.NotificationNormalContent().setTitle(title).setText(text);
        return new NotificationRequest.NotificationContent(content);
    }

    static class NotificationEventSubscriber extends CommonEventSubscriber {
        private final HmsMessageService slice;

        /**
         * Constructor
         *
         * @param subscribeInfo subscribe information
         * @param slice         slice who own the subscriber
         */
        public NotificationEventSubscriber(CommonEventSubscribeInfo subscribeInfo, HmsMessageService slice) {
            super(subscribeInfo);
            this.slice = slice;
        }

        @Override
        public void onReceiveEvent(CommonEventData commonEventData) {
            Intent intent = commonEventData.getIntent();
            if (intent == null) {
                return;
            }
            if (Const.NOTIFICATION_ACTION.equals(intent.getAction())) {
                PacMap pacMap = NotificationUserInput.getInputsFromIntent(intent);
                if (pacMap == null) {
                    return;
                }
                String inputText = pacMap.getString(Const.NOTIFICATION_INPUT_KEY);
                slice.getUITaskDispatcher().asyncDispatch(() -> {
                    Text replyText = (Text) slice.findComponentById(ResourceTable.Id_notify2_reply);
                    replyText.setText(inputText);
                });
            }
        }
    }
}